package com.ewancle.proxydownload.service;

import com.ewancle.proxydownload.config.ImageCompressionConfig;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Iterator;
import java.util.concurrent.ScheduledExecutorService;

// 3. 图片处理服务 - ImageProcessingService.java
@Service
public class ImageProcessingService {

    private final ImageCompressionConfig compressionConfig;
    private final ScheduledExecutorService virtualThreadScheduler;

    public ImageProcessingService(ImageCompressionConfig compressionConfig,
                                  ScheduledExecutorService virtualThreadScheduler) {
        this.compressionConfig = compressionConfig;
        this.virtualThreadScheduler = virtualThreadScheduler;
    }

    /**
     * 压缩图片并返回字节流
     */
    public Mono<byte[]> compressImage(byte[] originalImage, boolean enableCompression) {
        return Mono.fromCallable(() -> {
            System.out.println("enableCompression =  " + enableCompression);
            if (!enableCompression) {
                return originalImage;
            }

            try (ByteArrayInputStream bis = new ByteArrayInputStream(originalImage)) {
                BufferedImage image = ImageIO.read(bis);
                if (image == null) {
                    throw new IllegalArgumentException("无法读取图片数据");
                }

                // 调整图片尺寸
                //BufferedImage resizedImage = resizeImage(image);
                // 压缩图片
                //return compressBufferedImage(resizedImage);

                return compressBufferedImage(image);

            } catch (IOException e) {
                throw new RuntimeException("图片处理失败", e);
            }
        }).subscribeOn(Schedulers.fromExecutor(virtualThreadScheduler));
    }

    /**
     * 调整图片尺寸
     */
    private BufferedImage resizeImage(BufferedImage original) {
        int originalWidth = original.getWidth();
        int originalHeight = original.getHeight();

        if (originalWidth <= compressionConfig.getMaxWidth() &&
                originalHeight <= compressionConfig.getMaxHeight()) {
            return original;
        }

        double ratio = Math.min(
                (double) compressionConfig.getMaxWidth() / originalWidth,
                (double) compressionConfig.getMaxHeight() / originalHeight
        );

        int newWidth = (int) (originalWidth * ratio);
        int newHeight = (int) (originalHeight * ratio);

        BufferedImage resized = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = resized.createGraphics();

        // 高质量渲染设置
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        g2d.drawImage(original, 0, 0, newWidth, newHeight, null);
        g2d.dispose();

        return resized;
    }

    /**
     * 压缩BufferedImage
     */
    private byte[] compressBufferedImage(BufferedImage image) throws IOException {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(compressionConfig.getFormat());
            if (!writers.hasNext()) {
                throw new IllegalStateException("No writers found for format: " + compressionConfig.getFormat());
            }

            ImageWriter writer = writers.next();
            ImageWriteParam param = writer.getDefaultWriteParam();

            if (param.canWriteCompressed()) {
                param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                param.setCompressionQuality(compressionConfig.getQuality() / 100.0f);
            }

            if (param.canWriteProgressive() && compressionConfig.isProgressive()) {
                param.setProgressiveMode(ImageWriteParam.MODE_DEFAULT);
            }

            try (ImageOutputStream ios = ImageIO.createImageOutputStream(baos)) {
                writer.setOutput(ios);
                writer.write(null, new IIOImage(image, null, null), param);
                writer.dispose();
            }

            return baos.toByteArray();
        }
    }

    /**
     * 分块处理大图片流
     */
    public Flux<byte[]> processImageStream(Flux<byte[]> imageDataFlux, boolean enableCompression) {
        return imageDataFlux
                .collectList()
                .map(chunks -> {
                    int totalSize = chunks.stream().mapToInt(chunk -> chunk.length).sum();
                    byte[] fullImage = new byte[totalSize];
                    int offset = 0;
                    for (byte[] chunk : chunks) {
                        System.arraycopy(chunk, 0, fullImage, offset, chunk.length);
                        offset += chunk.length;
                    }
                    return fullImage;
                })
                .flatMap(fullImage -> compressImage(fullImage, enableCompression))
                .flatMapMany(processedImage -> {
                    // 将处理后的图片分块返回，减少内存占用
                    return Flux.fromIterable(chunkArray(processedImage, 8192));
                });
    }

    /**
     * 将字节数组分块
     */
    private java.util.List<byte[]> chunkArray(byte[] array, int chunkSize) {
        java.util.List<byte[]> chunks = new java.util.ArrayList<>();
        for (int i = 0; i < array.length; i += chunkSize) {
            int end = Math.min(array.length, i + chunkSize);
            byte[] chunk = new byte[end - i];
            System.arraycopy(array, i, chunk, 0, end - i);
            chunks.add(chunk);
        }
        return chunks;
    }
}